package com.fingard.dsp.bank.directbank.fc11.util;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSACoder extends Coder {
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

    private static final String PUBLIC_KEY = "123456";
    private static final String PRIVATE_KEY = "123456";

    public static void main(String[] args) throws Exception {
        // String source = "12sfdsfdsfs中文d";
        // String publicKey =
        // RSACoder.loadKey(RSACoder.class.getClassLoader().getResourceAsStream("key/test/test.cer"));
        // String privateKey =
        // RSACoder.loadKey(RSACoder.class.getClassLoader().getResourceAsStream("key/test/test.pfx"));
        // String sign = sign(source.getBytes("UTF-8"), privateKey);
        // boolean reslut = verify(source.getBytes("UTF-8"), publicKey, sign);
        // System.out.println(reslut);

        // 生成公私钥对
        genRSAKeyPair();

        String testStr = "{\"version\":\"1.0.0\",\"action\":\"platform_withdraw_action\",\"platformId\":\"2009061117PT25762148\",\"platformWithDrawId\":\"2012070317CP00000001\",\"platformWithDrawDate\":\"20120802181100\",\"withDrawAmount\":\"0.01\" ,\"bankAccountName\":\"测试\",\"bankAccountId\":\"6226198845678978\",\"cityId\":\"15\",\"bankId\":\"10\",\"currencyType\":\"00\"}";

        String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJid1nw+7rz5+7opcAybWchImwssjIr6Tw798Oaq9wgZ1aK/ZSbWoGmkyj3bw/ldxGwvSNdh8n1BtsT+rWd38TUe6LqFupBnwtH7NENfmHW5+jrOBdj1o/RlCAzSpILs4PsKSZi7Ph5BaCSekXOKSe8C/Etyi4VFmh2wPD9gBYhFAgMBAAECgYAXQb5EssZoz+N3bAciNK5K4h2WZ1SHfTt8+l+ylw0ME/vFUEtWztAlKTKUmJ/VqV9caRw9jjSIt/HlNTYxlUqRZHflatBAd/iNUEdUtN1dm3s2SHl8FftMionDWUXwjfdntHXkvST2tCpHY4F+MK9ATw4bc8INgCyv7sq25ZqZQQJBAM4Oax6X0vmEeMgX0qavzi4hArnQCRxA1eD1KMUnQ8TaoYwc1V+I6Z4/HJyQ5JN3vTDtSi+pvAE4qV1GJvNUytUCQQC9m4l+1FIFdDjuf/MC751ZH/KLNL8f0VQ/XmJFLt1KbP5rzlm46xCrpTXloQ51sdh0de9zFddB0AIW9nZWP5+xAkBsf1MQDMld8M7YLRMSCcf6qg8RX+UsJ0d26B/Lj90zLhuZ9ySy5Rh95qVeGz0AGTBZLti9OBZyXi9vmZywy5jxAkBMuGC8NwExP8PBjXgxGe+bHngvp5omL7ddJL2yrLHR6aRQzuAzGLpYGbNjRPXq3ZluFkJbWN0OvjH6RKPBZmEhAkAk1NZjltNt5sMwEgK0HThj8N8IFYlpZnmzh/Sp8SKRg2tlatKiAWGrca+uIvKQNOmADcBBNiGQdcTyV0THEv7x";
        String sign = sign(testStr.getBytes("UTF-8"), privateKey);
        System.out.println(sign);
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYndZ8Pu68+fu6KXAMm1nISJsLLIyK+k8O/fDmqvcIGdWiv2Um1qBppMo928P5XcRsL0jXYfJ9QbbE/q1nd/E1Hui6hbqQZ8LR+zRDX5h1ufo6zgXY9aP0ZQgM0qSC7OD7CkmYuz4eQWgknpFziknvAvxLcouFRZodsDw/YAWIRQIDAQAB";

        boolean reslut = verify(testStr.getBytes("UTF-8"), publicKey, sign);

        System.out.println(reslut);
    }

    /*
     * 产生RSA公私钥对
     */
    public static KeyPair genRSAKeyPair() {
        KeyPairGenerator rsaKeyGen = null;
        KeyPair rsaKeyPair = null;
        try {
            rsaKeyGen = KeyPairGenerator.getInstance("RSA");
            SecureRandom random = new SecureRandom();
            random.nextBytes(new byte[1]);
            rsaKeyGen.initialize(2048, new SecureRandom());
            rsaKeyPair = rsaKeyGen.genKeyPair();
            PublicKey rsaPublic = rsaKeyPair.getPublic();
            PrivateKey rsaPrivate = rsaKeyPair.getPrivate();

            System.out.println("公钥:" + Coder.encryptBASE64(rsaPublic.getEncoded()));
            System.out.println("私钥:" + Coder.encryptBASE64(rsaPrivate.getEncoded()));

        } catch (Exception e) {
            e.printStackTrace();
        }

        return rsaKeyPair;
    }

    /** */
    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       加密数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        // 解密由base64编码的私钥
        byte[] keyBytes = decryptBASE64(privateKey);

        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);

        return encryptBASE64(signature.sign());
    }

    public static String sign(byte[] data, PrivateKey priKey, String suite) throws Exception {

        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(suite);
        signature.initSign(priKey);
        signature.update(data);

        return encryptBASE64(signature.sign());
    }


    /** */
    /**
     * 校验数字签名
     *
     * @param data      加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {

        // 解密由base64编码的公钥
        byte[] keyBytes = decryptBASE64(publicKey);

        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);

        // 验证签名是否正常
        return signature.verify(decryptBASE64(sign));
    }

    /** */
    /**
     * 解密<br>
     * 用私钥解密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

    /** */
    /**
     * 解密<br>
     * 用私钥解密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

    /** */
    /**
     * 加密<br>
     * 用公钥加密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
        // 对公钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

    /** */
    /**
     * 加密<br>
     * 用私钥加密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

    /** */
    /**
     * 取得私钥
     *
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());
    }

    /** */
    /**
     * 取得公钥
     *
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());
    }

    /**
     * 初始化密钥
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(2048);

        KeyPair keyPair = keyPairGen.generateKeyPair();

        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /*
     * 获得秘钥
     */
    public static String loadKey(String filename) throws Exception {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(filename);
            byte[] b = new byte[1024];
            inputStream.read(b);
            return new String(b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return null;
    }

    /*
     * 获得秘钥
     */
    public static String loadKey(InputStream inputStream) throws Exception {
        try {
            byte[] b = new byte[1024];
            inputStream.read(b);
            return new String(b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return null;
    }

    /*
     * 获得私钥
     */
    public static RSAPrivateKey loadPrivateKey(String filename, String keyName, String pass) throws Exception {
        FileInputStream inKeyStoreFile = null;
        try {
            inKeyStoreFile = new FileInputStream(filename);
            char[] password = pass.toCharArray();
            KeyStore from = KeyStore.getInstance("JKS", "SUN");
            from.load(null, null);
            from.load(inKeyStoreFile, password);
            Key testkey = from.getKey(keyName, password);
            RSAPrivateKey pvtKey = (RSAPrivateKey) testkey;
            System.out.println("Private key exponent =\r\n" + pvtKey.getPrivateExponent().toString(16) + "\r\n");
            inKeyStoreFile.close();
            return pvtKey;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        } finally {
            if (inKeyStoreFile != null) {
                inKeyStoreFile.close();
            }
        }
    }

    /*
     * 获得公钥
     */
    public static RSAPublicKey loadPublicKey(String filename, String keyName, String pass) throws Exception {
        FileInputStream inKeyStoreFile = null;
        try {
            inKeyStoreFile = new FileInputStream(filename);
            char[] password = pass.toCharArray();
            KeyStore from = KeyStore.getInstance("JKS", "SUN");
            from.load(null, null);
            from.load(inKeyStoreFile, password);
            java.security.cert.Certificate c = from.getCertificate(keyName);
            RSAPublicKey pubKey = (RSAPublicKey) c.getPublicKey();
            System.out.println("Public key exponent =\r\n" + pubKey.getPublicExponent().toString(16) + "\r\n");
            inKeyStoreFile.close();
            return pubKey;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        } finally {
            if (inKeyStoreFile != null) {
                inKeyStoreFile.close();
            }
        }
    }

}
